using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
using Perovich.GameObjects;
using Perovich.GameObjects.Components.TwoDimensional;
using Perovich.GameObjects.Components.ThreeDimensional;
using Perovich.GameObjects.Components.Helpers;

#if WINDOWS_PHONE
using Microsoft.Devices.Sensors;
#endif

namespace ThreeDExampleProject
{
    public class FuelCarrier : InteractiveObject3D
    {
        #if WINDOWS_PHONE
        Motion motion;
        #endif

        public int MaxRange { get; set; }

        public FuelCarrier(Perovich.GameObjects.Interfaces.ICanHoldComponents game)
            : base(game)
        {
            MaxRange = 98;
            BoundingSphereScale = 0.8f;
            BoundingSphereOffset = new Vector3(0, 1, 0);
            GestureHelper.Initialize(game);
            GestureHelper.Instance.UpdateOrder = int.MinValue;
            GestureHelper.AddCallback(GestureType.Tap, KeyCallback);
            KeyboardHelper.Initialize(game);
            KeyboardHelper.AddCallback(Keys.Up, KeyboardCallback);
            KeyboardHelper.AddCallback(Keys.Down, KeyboardCallback);
            KeyboardHelper.AddCallback(Keys.Left, KeyboardCallback);
            KeyboardHelper.AddCallback(Keys.Right, KeyboardCallback);


            #if WINDOWS_PHONE
            if (!Motion.IsSupported)
            {
                //System.Windows.MessageBox.Show("the Motion API is not supported on this device.");
                return;
            }

            if (motion == null)
            {
                motion = new Motion();
                motion.TimeBetweenUpdates = TimeSpan.FromMilliseconds(2);
                motion.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<MotionReading>>(motion_CurrentValueChanged);
            }

            try
            {
                motion.Start();
            }
            catch (Exception e)
            {
                if ((e is UnauthorizedAccessException) || (e is InvalidOperationException) || (e is OutOfMemoryException) || (e is ObjectDisposedException) || (e is SensorFailedException))
                    System.Windows.MessageBox.Show("unable to start the Motion API.");
                else
                    throw;
            }
            #endif
            

        }

        #if WINDOWS_PHONE
        void motion_CurrentValueChanged(object sender, SensorReadingEventArgs<MotionReading> e)
        {
            if (e.SensorReading.Attitude.Pitch < MathHelper.ToRadians(-1))
            {
                Adown = Math.Min(-MathHelper.ToDegrees(e.SensorReading.Attitude.Pitch), MaxKeyDown);
            }
            else
            {
                Adown = 0.0f;
            }
            if (e.SensorReading.Attitude.Pitch > MathHelper.ToRadians(1))
            {
                Ddown = Math.Min(MathHelper.ToDegrees(e.SensorReading.Attitude.Pitch), MaxKeyDown);
            }
            else
            {
                Ddown = 0.0f;
            }

            if (e.SensorReading.Attitude.Roll < MathHelper.ToRadians(-1))
            {
                Sdown = Math.Min(-MathHelper.ToDegrees(e.SensorReading.Attitude.Roll), MaxKeyDown);
            }
            else
            {
                Sdown = 0.0f;
            }
            if (e.SensorReading.Attitude.Roll > MathHelper.ToRadians(1))
            {
                Wdown = Math.Min(MathHelper.ToDegrees(e.SensorReading.Attitude.Roll), MaxKeyDown);
            }
            else
            {
                Wdown = 0.0f;
            }
        }
        #endif
        float MaxKeyDown = 10.0f;
        float Wdown;
        float Adown;
        float Sdown;
        float Ddown;
        private void KeyboardCallback(Keys key, KeyState state)
        {
            if (state == KeyState.Down)
            {
                switch (key)
                {
                    case Keys.Up:
                        {
                            Wdown = 10;
                            break;
                        }
                    case Keys.Down:
                        {
                            Sdown = 10;
                            break;
                        }
                    case Keys.Left:
                        {
                            Adown = 10;
                            break;
                        }
                    case Keys.Right:
                        {
                            Ddown = 10;
                            break;
                        }
                }
            }
        }

        private void KeyCallback(GestureSample gs)
        {
            if (gs.Position.Y < 50)
            {
                Wdown = 10.0f;
            }
            else if (gs.Position.X < 50)
            {
                Adown = 10.0f;
            }
            else if (gs.Position.Y > GraphicsDevice.Viewport.Height - 50)
            {
                Sdown = 10.0f;
            }
            else if (gs.Position.X > GraphicsDevice.Viewport.Width - 50)
            {
                Ddown = 10.0f;
            }
        }


        public override void Update(GameTime gameTime)
        {
            

            Vector3 futurePosition;
            float turnAmount;


            turnAmount = 1 * (Adown / MaxKeyDown) + -1 * (Ddown / MaxKeyDown);

            RotationY += turnAmount * 0.025f;
            Matrix orientationMatrix = Matrix.CreateRotationY(RotationY);

            Vector3 movement = Vector3.Zero;

            movement.Z = 1 * (Wdown / MaxKeyDown) + -1 * (Sdown / MaxKeyDown);

            Vector3 speed = Vector3.Transform(movement, orientationMatrix);
            speed *= 0.75f;
            futurePosition = Position + speed;

            if (ValidateMovement(futurePosition))
            {
                Position = futurePosition;
            }
            #if WINDOWS_PHONE
            if (!Motion.IsSupported)
            {
            #endif
                Wdown = 0.0f;
                Adown = 0.0f;
                Sdown = 0.0f;
                Ddown = 0.0f;
            #if WINDOWS_PHONE
            }
            #endif
            base.Update(gameTime);
        }

        private bool ValidateMovement(Vector3 futurePosition)
        {
            //Don't allow off-terrain driving
            if ((Math.Abs(futurePosition.X) > MaxRange) ||
                (Math.Abs(futurePosition.Z) > MaxRange))
                return false;

            return true;
        }


        public void LoadContent(ContentManager content, string modelName)
        {
            ObjectModel = content.Load<Model>(modelName);
        }

    }
}
